﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Babylon.Toolbox;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Matrix = Microsoft.Xna.Framework.Matrix;

namespace SStuff.XnaInterop
{
    public static class InteropModelExtensions
    {
        public static Babylon.Toolbox.Model ToBabylonModel(this InteropModel source, GraphicsDevice device, Func<InteropMesh,InteropMeshPart, Effect> effectConverter){
            if(!source.IsPrepared)
                throw new ArgumentException("source InteropModel must be preapred");
            if(source.IndexBuffers.Length>1)
                throw new ArgumentException("Babylon Model system only supports a unique IndexBuffer");

            foreach (var interopMesh in source.Meshes)
            {
                if (interopMesh.Parts.Select(p => p.VertexBufferIndex).Distinct().Count() > 1)
                    throw new ArgumentException("Babylon Model does not supports meshes with multiple vertex / index buffers");
                if (interopMesh.Parts.Select(p => p.IndexBufferIndex).Distinct().Count() > 1)
                    throw new ArgumentException("Babylon Model does not supports meshes with multiple vertex / index buffers");
            }

            var meshes = new List<ModelMesh>();
            Matrix[] absoluteTransforms = new Matrix[source.Bones.Length];
            source.CopyAbsoluteBonesTo(absoluteTransforms);
            BoundingSphere modelBoundingSphere= new BoundingSphere();
            bool first = true;
            foreach (var imesh in source.Meshes){
                var mesh = new ModelMesh(imesh.BoneIndex);
                
                var boundingSphere = new BoundingSphere(new Vector3(imesh.BoundingSphereCenterX, imesh.BoundingSphereCenterY, imesh.BoundingSphereCenterZ), imesh.BoundingSphereRadius );
                boundingSphere.Transform(absoluteTransforms[imesh.BoneIndex]);
                mesh.BoundingSphere = boundingSphere;
                if (first){
                    first = false;
                    modelBoundingSphere = boundingSphere;
                }
                else{
                    BoundingSphere.CreateMerged(ref modelBoundingSphere, ref boundingSphere, out modelBoundingSphere);
                }
                mesh.SetBuffers(imesh.Parts[0].VertexBufferIndex, imesh.Parts[0].IndexBufferIndex, 0,0, imesh.Parts.Sum(p=>p.NumVertices));
                foreach (var ipart in imesh.Parts){
                    var part = new ModelMeshPart(mesh, false){
                        IndicesOffset = 0,
                        MinVertexIndex = 0,
                        NumVertices = ipart.NumVertices,
                        PrimitivesCount = ipart.PrimitiveCount,
                        StartIndex = ipart.StartIndex,
                        VerticesOffset = ipart.VertexOffset
                    };
                    part.Effect = effectConverter(imesh, ipart);
                }
                meshes.Add(mesh);
            }

            var result = new Babylon.Toolbox.Model(device, source.SL5VertexBuffers, source.SL5IndexBuffers,
                                                   meshes,
                                                   source.Bones.Select(
                                                       b => new Babylon.Toolbox.Bone(b.Name, b.Transform, b.IsRoot ? -1 : b.ParentIndex)));
            result.BoundingSphere = modelBoundingSphere;
            return result;
        }
    }
}
